/*
  @author: remy sharp / http://remysharp.com
  @params:
    feedback - the selector for the element that gives the user feedback. Note that this will be relative to the form the plugin is run against.
    hardLimit - whether to stop the user being able to keep adding characters. Defaults to true.
    useInput - whether to look for a hidden input named 'maxlength' instead of the maxlength attribute. Defaults to false.
    words - limit by characters or words, set this to true to limit by words. Defaults to false.
  @license: Creative Commons License - ShareAlike http://creativecommons.org/licenses/by-sa/3.0/
  @version: 1.2
  @changes: code tidy via Ariel Flesler and fix when pasting over limit and including \t or \n
  
  @changes: add maxlength params - which identify the maxlength of the target control  --www.jyoule.com 2011.1.26
 */

(function($) {

	$.fn.maxlength = function(settings) {
		if (typeof settings == 'string') {
			settings = {
				feedback : settings
			};
		}

		settings = $.extend({}, $.fn.maxlength.defaults, settings);

		function length(el) {
			var parts = el.value;
			if (settings.words)
				parts = el.value.length ? parts.split(/\s+/) : {
					length : 0
				};
			return parts.length;
		}

		return this
				.each(function() {
					var field = this, $field = $(field), $form = $(field.form), limit = settings.useInput ? $form
							.find('#' + settings.maxlength).val()
							: $field.attr('maxlength'), $charsLeft = $form
							.find('#' + settings.feedback);

					function limitCheck(event) {
						var len = length(this), exceeded = len >= limit, code = event.keyCode;

						if (!exceeded)
							return;

						switch (code) {
						case 8: // allow delete
						case 9:
						case 17:
						case 36: // and cursor keys
						case 35:
						case 37:
						case 38:
						case 39:
						case 40:
						case 46:
						case 65:
							return;

						default:
							return settings.words && code != 32 && code != 13
									&& len == limit;
						}
					}

					var updateCount = function() {
						var len = length(field), diff = limit - len;
						$charsLeft.html(diff || "0");

						// truncation code
						if (settings.hardLimit && diff < 0) {
							field.value = settings.words ?
							// split by white space, capturing it in the result,
							// then glue them back
							field.value.split(/(\s+)/, (limit * 2) - 1)
									.join('') : field.value.substr(0, limit);

							updateCount();
						}
					};

					$field.keyup(updateCount).change(updateCount);
					if (settings.hardLimit) {
						$field.keydown(limitCheck);
					}

					updateCount();
				});
	};

	$.fn.maxlength.defaults = {
		useInput : false,
		hardLimit : true,
		feedback : 'charsleft',
		words : false,
		maxlength : 'maxlength'
	};

})(jQuery);
